知道怎麼構建UI後,我們來學學怎麼跟UI的互動
最簡單的方式就是新增Modifier.clickable,比如說新增text被點擊事件:
Text(
text = "123",
modifier = Modifier.clickable { Log.d("clickable", "click!") }
)
點擊之後就會出現:
D/clickable: click!
那如果搭配昨天的mutableStateOf的使用方式:
val count = remember { mutableStateOf(0) }
Text(
text = count.value.toString(),
modifier = Modifier.clickable { count.value += 1 }
)
記得第一行要在composable的範圍裏面,不能宣告成一般kotlin的全域或區域變數,那我們就完成了一個每點一下就會加一的計數器++++++
如果想要實現原本的onTouchEvent能完成的事件偵測,那可以使用Modifier.pointerInput來完成,裡面則是依照需求放入PointerInputScope.detectTapGestures或 PointerInputScope.detectDragGestures:
點擊偵測:
Modifier.pointerInput(Unit) {
detectTapGestures(
onPress = { /* Called when the gesture starts */ },
onDoubleTap = { /* Called on Double Tap */ },
onLongPress = { /* Called on Long Press */ },
onTap = { /* Called on Tap */ }
)
}
拖動效果:
suspend fun PointerInputScope.detectDragGestures(
onDragStart: (Offset) -> Unit = { },
onDragEnd: () -> Unit = { },
onDragCancel: () -> Unit = { },
onDrag: (PointerInputChange, Offset) -> Unit
): Unit
或是我們可以使用底下的code來實現橫向的拖動:
var offsetX by remember { mutableStateOf(0f) }
Text(modifier = Modifier
.offset {
IntOffset(offsetX.roundToInt(), 0)
}
.draggable(
orientation = Orientation.Horizontal,
state = rememberDraggableState(onDelta = { delta ->
offsetX += delta
}
)
),
text = "Drag me!")
offset可以實現元件的偏移位置,因為我們只移動X軸,所以y軸維持0,X軸的位置則是從offsetX.roundToInt()來讀取,然後使用rememberDraggableState來更新拖動的位置。
有時候會有需要實作功能開關,或者非連續的狀態切換的話,可以使用swiping來達成這個目標,同時我們也可以設定當滑動過半的時候,使用anchors讓要活動的對象直接切換到對應的位:
swipeableState:通过 swipeableState 的设置可以獲得現在元件移動到哪裡
anchors:可以設置在不同狀態時所對應的不偏移量,
orientation:手勢的方向
於是我們時現的方式就來了:
val width = 200.dp
val squareSize = 100.dp
val swipeableState = rememberSwipeableState(0)
val sizePx = with(LocalDensity.current) { squareSize.toPx() }
val anchors = mapOf(0f to 0, sizePx to 1)
Box(
modifier = Modifier
.width(width)
.swipeable(
state = swipeableState,
anchors = anchors,
orientation = Orientation.Horizontal
)
.background(Color.LightGray)
) {
Box(
Modifier
.offset { IntOffset(swipeableState.offset.value.roundToInt(), 0) }
.size(squareSize)
.background(Color.DarkGray)
)
}
with(LocalDensity.current) { 16.dp.toPx() } 可以先當作把dp轉成px的一種方式,然後開關的判斷方式,是利用我們定義的anchors來決定是0還是1,這樣我們定義的box就會利用offset對應到0或者是1的位置。